package xyz.xiezc.spider.prase;

import cn.hutool.setting.Setting;
import lombok.Data;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import xyz.xiezc.ioc.annotation.Component;
import xyz.xiezc.ioc.annotation.Inject;
import xyz.xiezc.spider.common.BaseDO;
import xyz.xiezc.spider.common.MediaType;
import xyz.xiezc.spider.common.Response;
import xyz.xiezc.spider.common.XBean;
import xyz.xiezc.spider.common.annotation.InstanceDefine;
import xyz.xiezc.spider.common.annotation.MatchBeanAnnotationHandler;
import xyz.xiezc.spider.common.annotation.MatchField;
import xyz.xiezc.spider.common.annotation.NextRequest;
import xyz.xiezc.spider.control.Schedule;

import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.*;

/**
 * @author wb-xzc291800
 * @date 2019/04/04 13:24
 */
//@Component
@Data
public class ParseHtmlImpl implements ParseResponse {

    @Inject
    private MatchBeanAnnotationHandler matchBeanAnnotationHandler;
    @Inject
    private Schedule schedule;

    @Inject
    Setting setting;

    String imgDir;

    public void init() {
        imgDir = setting.getStr("data.dir");
    }

    /**
     * @param xBean
     * @return
     * @throws Exception
     */
    private Object getByUrl(XBean xBean) throws Exception {
        String url = xBean.getRequest().getUrl();
        List<InstanceDefine> instanceDefineList = matchBeanAnnotationHandler.instanceDefineList;
        BaseDO getBean = null;
        InstanceDefine matchInstanceDefine = null;
        for (InstanceDefine instanceDefine : instanceDefineList) {
            getBean = instanceDefine.getByUrlStr(url);
            if (getBean != null) {
                matchInstanceDefine = instanceDefine;
                xBean.setBean(Arrays.asList(getBean));
                break;
            }
        }
        if (getBean != null) {
            parseDom(xBean, getBean, matchInstanceDefine);
        }
        return getBean;
    }

    private void parseDom(XBean xBean, BaseDO getBean, InstanceDefine matchInstanceDefine) throws IllegalAccessException {
        Response response = xBean.getResponse();
        //TODO  这里还要考虑不同的网站编码的问题
        MediaType mediaType = response.getMediaType();
        if (mediaType.getContentType().contains("text/html")) {
            Charset charset = response.getCharset();
            String bodyStr = new String(response.getBodyByte(), charset);

            Document document = Jsoup.parse(bodyStr);

            Map<Field, MatchField> matchFieldMap = matchInstanceDefine.getMatchFieldMap();
            Map<Field, NextRequest> nextRequestMap = matchInstanceDefine.getNextRequestMap();
            Set<Map.Entry<Field, MatchField>> entries = matchFieldMap.entrySet();
            for (Map.Entry<Field, MatchField> entry : entries) {
                MatchField key = entry.getValue();

                this.parseBySelect(document, key.value(), key.attr(), entry.getKey(), getBean);
            }
            Set<Map.Entry<Field, NextRequest>> entries1 = nextRequestMap.entrySet();
            for (Map.Entry<Field, NextRequest> entry : entries1) {
                NextRequest key = entry.getValue();
                this.parseBySelect(document, key.value(), key.attr(), entry.getKey(), getBean);
            }
        }
    }


    /**
     * 根据注解配置的选择器 提取网页中的对应元素的文本, 并且赋值到对象中
     *
     * @param document
     * @param selectStr
     * @param field
     * @param obj
     * @throws IllegalAccessException
     */
    private void parseBySelect(Document document, String selectStr, String attr, Field field, Object obj) throws IllegalAccessException {
        Elements elements = document.select(selectStr);
        List<String> list = new ArrayList<>();
        elements.forEach(element -> {
            String text = null;
            if (Objects.equals(attr, "")) {
                text = element.toString();
            } else if (Objects.equals(attr, "text")) {
                text = element.text();
            } else if (Objects.equals(attr, "html")) {
                text = element.html();
            } else {
                text = element.attr(attr);
            }
            list.add(text);
        });
        if (list.isEmpty()) {
            return;
        }
        Class<?> type = field.getType();
        //如果装载字段是字符串
        if (String.class.isAssignableFrom(type)) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            field.set(obj, list.get(0));
            return;
        }

        //如果装载字段是Str数组
        if (type.isArray()) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            field.set(obj, list.toArray(new String[0]));
            return;
        }

        //如果装载字段是集合
        if (List.class.isAssignableFrom(type)) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            field.set(obj, list);
            return;
        }
        if (Set.class.isAssignableFrom(type)) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            Set<String> set = new HashSet<>();
            set.addAll(list);
            field.set(obj, set);
            return;
        }
    }


    @Override
    public XBean parse(XBean xBean)  {
        try {
            this.getByUrl(xBean);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return xBean;
    }
}
